// Package validator
// Title 			playground.components.go
// Description 		Nacos 注册中心工厂, 实现 factory.ApplicationRegistryLoaderFactory, 实现其远程加载器接口方法
// Author  			alittlexincan@163.com 					2024/07/22 11:36
// Update  			alittlexincan@163.com 					2024/07/22 11:36
package validator

import (
	"reflect"

	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	trans "github.com/go-playground/validator/v10/translations/zh"
	"go.uber.org/zap"
	"xincan.com.cn/tarot-go/internal/components/logging"
)

// Validator
// Title    			Validator
// Description   		验证器结构体
// Author      			alittlexincan@163.com       			2024/07/22 11:36
// Update  			alittlexincan@163.com       				2024/07/22 11:36
type Validator struct {

	// Validate 验证器
	Validate *validator.Validate

	// Trans 翻译器
	Trans *ut.Translator

	// Rules 自定义规则
	Rules map[string]*ValidRuleInfo
}

// playgroundValidatorComponent
// Title 			playgroundValidatorComponent
// Description 		参数验证器结构体
// Author  			alittlexincan@163.com 								2024/07/22 11:36
// Update  			alittlexincan@163.com 								2024/07/22 11:36
type playgroundValidatorComponent struct {

	// logger 日志组件
	logger *logging.TraceLogger
}

// PlaygroundValidatorComponentBuilder
// Title 			PlaygroundValidatorComponentBuilder
// Description 		参数验证器构造器结构体
// Author  			alittlexincan@163.com 								2024/07/22 11:36
// Update  			alittlexincan@163.com 								2024/07/22 11:36
type PlaygroundValidatorComponentBuilder struct {
	*playgroundValidatorComponent
}

// NewPlaygroundValidatorComponentBuilder
// Title NewPlaygroundValidatorComponentBuilder
// Description 		创建参数验证器构造器实例
// Author  			alittlexincan@163.com 								2024/07/22 11:36
// Update  			alittlexincan@163.com 								2024/07/22 11:36
// Return    		*PlaygroundValidatorBuilder    						返回参数验证器构造器实例
func NewPlaygroundValidatorComponentBuilder() *PlaygroundValidatorComponentBuilder {
	return &PlaygroundValidatorComponentBuilder{
		&playgroundValidatorComponent{},
	}
}

// WithLogger
// Title 			WithLogger
// Description 		设置日志组件
// Author  			alittlexincan@163.com 								2024/07/22 11:36
// Update  			alittlexincan@163.com 								2024/07/22 11:36
// Param    		logger *logging.TraceLogger 						传入日志组件
// Return    		*PlaygroundValidatorBuilder    						返回参数验证器构造器实例
func (builder *PlaygroundValidatorComponentBuilder) WithLogger(logger *logging.TraceLogger) *PlaygroundValidatorComponentBuilder {
	builder.logger = logger
	return builder
}

// Build
// Title Build
// Description 		创建参数验证器实例
// Author  			alittlexincan@163.com 								2024/07/22 11:36
// Update  			alittlexincan@163.com 								2024/07/22 11:36
// Return    		*playgroundValidator    							返回参数验证器实例
func (builder *PlaygroundValidatorComponentBuilder) Build() *Validator {
	return builder.validateLoad()
}

// validateLoad
// Title validateLoad
// Description 		加载验证框架
// Author  			alittlexincan@163.com 								2024/07/22 11:36
// Update  			alittlexincan@163.com 								2024/07/22 11:36
// Return    		*Validator    										返回参数验证器实例
func (pg *playgroundValidatorComponent) validateLoad() *Validator {
	validate := validator.New(validator.WithRequiredStructEnabled())
	uni := ut.New(zh.New())
	translator, _ := uni.GetTranslator("zh")
	// 注册中文翻译
	if err := trans.RegisterDefaultTranslations(validate, translator); err != nil {
		pg.logger.Error("加载验证框架配置: 注册中文插件失败", zap.Error(err))
	}
	// 注册自定义标签
	validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
		return fld.Tag.Get("label")
	})

	// 获取所有校验规则, 注册自定义验证器的翻译、规则校验
	rules := NewRuleValidatorBuilder().WithLogger(pg.logger).WithValidator(validate).WithTrans(translator).Build()
	for label, rule := range rules {

		if err := rule.TranslateFunc(); err != nil {
			pg.logger.Error("加载验证框架配置: 注册自定义验证器失败: ["+label+"]: ", zap.Error(err))
		}
		if err := validate.RegisterValidation(label, rule.RuleFunc); err != nil {
			pg.logger.Error("加载验证框架配置: 注册自定义验证器失败: ["+string(label)+"]: ", zap.Error(err))
		}
	}
	pg.logger.Info("加载验证框架成功")
	// 创建验证器实例,并返回
	return &Validator{
		Validate: validate,
		Trans:    &translator,
		Rules:    rules,
	}
}
